package org.springframework.context;

import org.springframework.beans.factory.annotation.Autowried;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Garrett.Xia
 * @date 2021/11/5 0005 - 9:42
 */
public class AnnotationApplicationContext {
    private String basePackage;

    private static ConcurrentHashMap<String, Object> beanFactory = new ConcurrentHashMap<>();

    public AnnotationApplicationContext(String basePackage) {
        this.basePackage = basePackage;
        this.initBeans();
        Collection<Object> beans = beanFactory.values();
        for (Object bean: beans){
            this.injectDependencies(bean);
        }
    }

    private void initBeans(){
        List<Class<?>> classes = ClassUtils.getClasses(basePackage);
        for (Class<?> clz : classes) {
            Service annotation = clz.getAnnotation(Service.class);
            if (annotation != null) {
                Object bean = null;
                try {
                    bean = clz.newInstance();
                } catch (InstantiationException e) {
                    System.out.printf("实例化bean：%s失败", clz.toString());
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    System.out.printf("%s访问权限不够", clz.toString());
                    e.printStackTrace();
                }
                String beanId = this.toLowerCaseFirstChar(clz.getSimpleName());
                beanFactory.put(beanId, bean);
            }
        }
    }

    private String toLowerCaseFirstChar(String className) {
        StringBuilder stringBuilder = new StringBuilder(className.substring(0,1).toLowerCase());
        stringBuilder.append(className.substring(1));
        return stringBuilder.toString();
    }

    private void injectDependencies(Object bean){
        Class<?> clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            Autowried annotations = field.getAnnotation(Autowried.class);
            if (annotations != null) {
                // 如果标注了@Autowired注解，则需要依赖注入
                Object object = beanFactory.get(field.getName());
                // 如果访问权限不够，需要设置此项
                field.setAccessible(true);
                try {
                    // 依赖注入
                    field.set(bean, object);
                } catch (IllegalAccessException e){
                    e.printStackTrace();
                }
            }
        }
    }

    public Object getBean(String beanId) {
        return beanFactory.get(beanId);
    }
}
